#pragma once

template <class Derived, class CellT, template<class> class GridT >
class Generic2DCA
{
public:
  int getWidth() const { return m_width; }
  int getHeight() const { return m_height; }

  void setConstBound(const CellT & cell) { m_grid.setConstBound(cell); }
  void setTorusBound() { m_grid.setTorusBound(); }

  const CellT & getCell(int x, int y) const { return m_grid.getCell(x, y); }
  void setCell(int x, int y, const CellT & cell) { m_grid.setCell(x, y, cell); }

  void iterate()
  {
    m_grid.setWriteBuffer( 1 - m_grid.getReadBuffer() );
    m_grid.walkAllCells(Derived::Visitor( *static_cast<Derived*>(this) ));
    m_grid.setReadBuffer( m_grid.getWriteBuffer() );
    ++m_iteration;
  }

  int getIteration() const { return m_iteration; }
  void resetIteration() { m_iteration = 0; }

protected:
  typedef GridT<CellT> GridType;

  Generic2DCA(int width, int height) 
    : m_width(width), m_height(height), m_iteration(0),
    m_grid(width, height, 2)
  {
    setTorusBound();
  }

private:
  int m_iteration;

  int m_width;
  int m_height;
  GridType m_grid;
};
